#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include "ason_socket.h"


/*check parameter is invalid or not*/
#define ASON_CHECK_PARAM(param) \
	if (NULL == param) \
	{\
		printf("parameter is invalid\n");\
		return -1;\
	}
	
#define ASON_RCV_MSG_TIME_OUT	2



static int _create_server_udp(unsigned short port);
static int _rcv_msg(char *msg,char len,struct sockaddr_in *client_addr);
static int _send_msg(char *msg,char len,struct sockaddr_in *client_addr);
static int _sock_destroy();


static int s_sock_id = 0;/*server socket id*/

int ason_sock_register(ason_sock_obj_t *sock_obj)
{
	ASON_CHECK_PARAM(sock_obj)
	
	sock_obj->create_server = _create_server_udp;
	sock_obj->send = _send_msg;
	sock_obj->rcv = _rcv_msg;
	sock_obj->destroy = _sock_destroy;
	
	return 0;
}

static int _create_server_udp(unsigned short port)
{
	int		sock;
	struct	sockaddr_in	ser_addr;
	
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	ser_addr.sin_port = htons(port);
	
	sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if (sock < 0)
	{
		ASON_DEBUG("%s",strerror(errno));
		return -1;
	}
	
	if (bind(sock,(struct sockaddr*)&ser_addr,sizeof(ser_addr)) < 0)
	{
		ASON_DEBUG("%s",strerror(errno));
		return -1;
	}
	
	s_sock_id = sock;

	return 0;
}

/*receive message the return value is message buff length*/
static int _rcv_msg(char *msg,char len,struct sockaddr_in *client_addr)
{
	int 		status = 0;
	int			rcv_len = 0;
	int 		sock_len = sizeof(struct sockaddr_in);
	struct sockaddr_in 	cli_addr;
	struct timeval   	tv;
	fd_set				set;
	
	ASON_CHECK_PARAM(msg)
	ASON_CHECK_PARAM(client_addr)
	
	
	memset(&cli_addr,0,sizeof(cli_addr));
	
	FD_ZERO(&set);
	FD_SET(s_sock_id,&set);
	tv.tv_sec   =   ASON_RCV_MSG_TIME_OUT;         
	tv.tv_usec   =   0;
	
	status = select(s_sock_id+1,&set,NULL,NULL,&tv);
	
	if (status > 0)
	{
		if (FD_ISSET(s_sock_id,&set))
		{
		
			if ((rcv_len=recvfrom(s_sock_id,msg,len,0,
					(struct sockaddr *)&cli_addr,
					(socklen_t *)&sock_len)) <= 0)
			{
				ASON_DEBUG("receive message is null.error is %s",strerror(errno));
				return -1;
			}
			
			memcpy(client_addr,&cli_addr,sizeof(struct sockaddr_in));
			/*the return value is message buff length*/
			return rcv_len;
		}
	}
	else if (status == 0)
	{
		printf("receive message is null...\n");
	}
	else
	{
		ASON_DEBUG("receive message error...");
	}
	
	return status;
}

/*send message*/
static int _send_msg(char *msg,char len,struct sockaddr_in *client_addr)
{
	int sock_len = sizeof(struct sockaddr_in);
	struct sockaddr_in 	cli_addr;
	
	ASON_CHECK_PARAM(msg)
	ASON_CHECK_PARAM(client_addr)
	
	
	memset(&cli_addr,0,sizeof(cli_addr));
	memcpy(&cli_addr,client_addr,sizeof(cli_addr));
	
	if(cli_addr.sin_addr.s_addr == 0x0)
	{
		ASON_DEBUG("client ipaddr have not be set.\n");
		return -1;
	}
	
	if (sendto(s_sock_id, msg, len, 0,
			(struct sockaddr*)&cli_addr, sock_len)<=0)
	{
		ASON_DEBUG("send message fail.\n");
		return -1;
	}
	
	return 0;
}

static int _sock_destroy()
{
	close(s_sock_id);	
	
	return 0;
}

/*
int main(int argc, char *argv[])
{
	ason_sock_obj_t sock_obj;
	struct sockaddr_in client_addr;
	ason_sock_register(&sock_obj);
	sock_obj.create_server(1234);
	
	char msg_buff[128];
	
	while(1)
	{
		memset(msg_buff,0,sizeof(msg_buff));
		if (sock_obj.rcv(msg_buff,sizeof(msg_buff),&client_addr))
		{
			ASON_DEBUG("msg_buff=%s",msg_buff);
		}
	
	}
	
	sock_obj.destroy();

	return 0;
}
*/